#pragma once

// clang-format off

// cat(a, b) => ab
#define SFC_CAT(a, b)       _SFC_CAT_A((a, b))
#define _SFC_CAT_A(...)     _SFC_CAT_B __VA_ARGS__
#define _SFC_CAT_B(a, b)    a##b

// count(...)
#define SFC_CNT(...)     _SFC_CNT(x,##__VA_ARGS__,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)
#define _SFC_CNT(x,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,d0,d1,d2,d3,d5,d6,d7,d8,d9,e0,e1,e2,e3,e4,e5,e6,e7,e8,e9,N, ...) N

#define SFC_EMPTY()
#define SFC_COMMA()  ,
#define SFC_SEMICOLON() ;

// foreach(...)
#define SFC_FOREACH(F, ...)       SFC_CAT(_SFC_FOR_,SFC_CNT(__VA_ARGS__))(F, SFC_EMPTY, __VA_ARGS__)
#define SFC_FOREACH_(F, D,...)    SFC_CAT(_SFC_FOR_,SFC_CNT(__VA_ARGS__))(F, D, __VA_ARGS__)

#define _SFC_FOR_0( F,D,x, ...)
#define _SFC_FOR_1( F,D,x, ...) F(x)
#define _SFC_FOR_2( F,D,x, ...) F(x) D() _SFC_FOR_1( F,D,__VA_ARGS__)
#define _SFC_FOR_3( F,D,x, ...) F(x) D() _SFC_FOR_2( F,D,__VA_ARGS__)
#define _SFC_FOR_4( F,D,x, ...) F(x) D() _SFC_FOR_3( F,D,__VA_ARGS__)
#define _SFC_FOR_5( F,D,x, ...) F(x) D() _SFC_FOR_4( F,D,__VA_ARGS__)
#define _SFC_FOR_6( F,D,x, ...) F(x) D() _SFC_FOR_5( F,D,__VA_ARGS__)
#define _SFC_FOR_7( F,D,x, ...) F(x) D() _SFC_FOR_6( F,D,__VA_ARGS__)
#define _SFC_FOR_8( F,D,x, ...) F(x) D() _SFC_FOR_7( F,D,__VA_ARGS__)
#define _SFC_FOR_9( F,D,x, ...) F(x) D() _SFC_FOR_8( F,D,__VA_ARGS__)
#define _SFC_FOR_10(F,D,x, ...) F(x) D() _SFC_FOR_9( F,D,__VA_ARGS__)
#define _SFC_FOR_11(F,D,x, ...) F(x) D() _SFC_FOR_10(F,D,__VA_ARGS__)
#define _SFC_FOR_12(F,D,x, ...) F(x) D() _SFC_FOR_11(F,D,__VA_ARGS__)
#define _SFC_FOR_13(F,D,x, ...) F(x) D() _SFC_FOR_12(F,D,__VA_ARGS__)
#define _SFC_FOR_14(F,D,x, ...) F(x) D() _SFC_FOR_13(F,D,__VA_ARGS__)
#define _SFC_FOR_15(F,D,x, ...) F(x) D() _SFC_FOR_14(F,D,__VA_ARGS__)
#define _SFC_FOR_16(F,D,x, ...) F(x) D() _SFC_FOR_15(F,D,__VA_ARGS__)
#define _SFC_FOR_17(F,D,x, ...) F(x) D() _SFC_FOR_16(F,D,__VA_ARGS__)
#define _SFC_FOR_18(F,D,x, ...) F(x) D() _SFC_FOR_17(F,D,__VA_ARGS__)
#define _SFC_FOR_19(F,D,x, ...) F(x) D() _SFC_FOR_18(F,D,__VA_ARGS__)
#define _SFC_FOR_20(F,D,x, ...) F(x) D() _SFC_FOR_19(F,D,__VA_ARGS__)
#define _SFC_FOR_21(F,D,x, ...) F(x) D() _SFC_FOR_20(F,D,__VA_ARGS__)
#define _SFC_FOR_22(F,D,x, ...) F(x) D() _SFC_FOR_21(F,D,__VA_ARGS__)
#define _SFC_FOR_23(F,D,x, ...) F(x) D() _SFC_FOR_22(F,D,__VA_ARGS__)
#define _SFC_FOR_24(F,D,x, ...) F(x) D() _SFC_FOR_23(F,D,__VA_ARGS__)
#define _SFC_FOR_25(F,D,x, ...) F(x) D() _SFC_FOR_24(F,D,__VA_ARGS__)
#define _SFC_FOR_26(F,D,x, ...) F(x) D() _SFC_FOR_25(F,D,__VA_ARGS__)
#define _SFC_FOR_27(F,D,x, ...) F(x) D() _SFC_FOR_26(F,D,__VA_ARGS__)
#define _SFC_FOR_28(F,D,x, ...) F(x) D() _SFC_FOR_27(F,D,__VA_ARGS__)
#define _SFC_FOR_29(F,D,x, ...) F(x) D() _SFC_FOR_28(F,D,__VA_ARGS__)
#define _SFC_FOR_30(F,D,x, ...) F(x) D() _SFC_FOR_29(F,D,__VA_ARGS__)
#define _SFC_FOR_31(F,D,x, ...) F(x) D() _SFC_FOR_30(F,D,__VA_ARGS__)
#define _SFC_FOR_32(F,D,x, ...) F(x) D() _SFC_FOR_31(F,D,__VA_ARGS__)
#define _SFC_FOR_33(F,D,x, ...) F(x) D() _SFC_FOR_32(F,D,__VA_ARGS__)
#define _SFC_FOR_34(F,D,x, ...) F(x) D() _SFC_FOR_33(F,D,__VA_ARGS__)
#define _SFC_FOR_35(F,D,x, ...) F(x) D() _SFC_FOR_34(F,D,__VA_ARGS__)
#define _SFC_FOR_36(F,D,x, ...) F(x) D() _SFC_FOR_35(F,D,__VA_ARGS__)
#define _SFC_FOR_37(F,D,x, ...) F(x) D() _SFC_FOR_36(F,D,__VA_ARGS__)
#define _SFC_FOR_38(F,D,x, ...) F(x) D() _SFC_FOR_37(F,D,__VA_ARGS__)
#define _SFC_FOR_39(F,D,x, ...) F(x) D() _SFC_FOR_38(F,D,__VA_ARGS__)
#define _SFC_FOR_40(F,D,x, ...) F(x) D() _SFC_FOR_29(F,D,__VA_ARGS__)
#define _SFC_FOR_41(F,D,x, ...) F(x) D() _SFC_FOR_40(F,D,__VA_ARGS__)
#define _SFC_FOR_42(F,D,x, ...) F(x) D() _SFC_FOR_41(F,D,__VA_ARGS__)
#define _SFC_FOR_43(F,D,x, ...) F(x) D() _SFC_FOR_42(F,D,__VA_ARGS__)
#define _SFC_FOR_44(F,D,x, ...) F(x) D() _SFC_FOR_43(F,D,__VA_ARGS__)
#define _SFC_FOR_45(F,D,x, ...) F(x) D() _SFC_FOR_44(F,D,__VA_ARGS__)
#define _SFC_FOR_46(F,D,x, ...) F(x) D() _SFC_FOR_45(F,D,__VA_ARGS__)
#define _SFC_FOR_47(F,D,x, ...) F(x) D() _SFC_FOR_46(F,D,__VA_ARGS__)
#define _SFC_FOR_48(F,D,x, ...) F(x) D() _SFC_FOR_47(F,D,__VA_ARGS__)
#define _SFC_FOR_49(F,D,x, ...) F(x) D() _SFC_FOR_48(F,D,__VA_ARGS__)
// clang-format on
